// const Webrtc2SipInstances = new Set();

class Webrtc2Sip {
  static instances; // 已实例化的对象
  static globalSessionEvent; // 会话回调事件
  static globalStackEvent; // sip栈回调事件
  static globalCustomSessionEvent; // 自定义会话回调事件
  static globalCustomStackEvent; // 自定义sip栈回调事件
  static ringtone; // 铃声
  static ringbacktone; // 回铃声
  static audioRemote; // 回铃声
  static isInited = false; // 是否初始化
  static webrtc2SipEnabled = false; // 是否启用

  constructor(options) {
    if (!SIPml.isInitialized()) throw new Error('请先初始化');
    postConstruct.call(this, options);
  }
  /**
   * 初始化
   * @param {Fuction} sessionEvent 会话回调事件
   * @param {Fuction} stackEvent sip栈回调事件
   * @param {String} debugLevel sip console日志等级
   */
  static init(sessionEvent, stackEvent, options) {
    // debugLevel = 'error'
    this.instances = new Map();
    this.setGlobalEvent(sessionEvent, stackEvent);
    this.ringtone = document.getElementById(options.ringtone);
    this.ringbacktone = document.getElementById(options.ringbacktone);
    this.audioRemote = document.getElementById(options.audioRemote);
    this.videoRemote = document.getElementById(options.videoRemote);
    this.videoLocal = document.getElementById(options.videoLocal);
    if (SIPml) {
      SIPml.init();
      SIPml.setDebugLevel(options.debugLevel ? options.debugLevel : 'error');
    }
    this.isInited = true;
    this.callType = '';
  }
  // 获取已实例化的Webrtc2Sip对象
  static getInstances() {
    return [...this.instances.values()];
  }

  // 销毁Webrtc2Sip所有实例
  static destroy() {
    for (const item of this.instances.values()) {
      item.unRegister();
    }
  }

  // 是否启用webrtc2sip
  static isEnabled() {
    return this.webrtc2SipEnabled;
  }
  /**
   * 根据号码判断是否启用
   * @param {String} name 号码
   */
  static isExistForName(name) {
    return this.getWebrtc2SipByName(name) ? true : false;
  }

  /**
   * 设置全局回调事件
   * @param {Functon} sessionEvent
   * @param {Functon} stackEvent
   */
  static setGlobalEvent(sessionEvent, stackEvent) {
    if (sessionEvent && stackEvent) {
      this.globalSessionEvent = sessionEvent;
      this.globalStackEvent = stackEvent;
    } else {
      throw new Error('session事件和stack事件必须同时存在');
    }
  }

  /**
   * 设置全局自定义回调事件
   * @param {Functon} sessionEvent
   * @param {Functon} stackEvent
   */
  static setGlobalCustomEvent(sessionEvent, stackEvent) {
    this.globalCustomSessionEvent = sessionEvent;
    this.globalCustomStackEvent = stackEvent;
  }

  /**
   * 检查是否支持WebRTC
   */
  static isWebRtcSupported() {
    return SIPml.isWebRtcSupported() && SIPml.isWebSocketSupported();
  }

  /**
   * 通过号码获取webrt2sip对象
   * @param {String} name 号码
   */
  static getWebrtc2SipByName(name) {
    return this.instances.get(name);
  }

  /**
   * 通过号码清除自定义事件
   * @param {String} name 号码
   */
  static clearCustomEventByName(name) {
    const item = this.instances.get(name);
    if (item) item.clearCustomEvent();
  }

  /**
   * 设置自定义事件，优先级别高于全局事件，有自定义事件后不再调用全局事件，如需要调用可以在自定义事件里面用Webrtc2Sip类调用，
   * 注意：离开页面时需要清除自定义事件
   */
  setCustomEvent(sessionEvent, stackEvent) {
    if (sessionEvent && stackEvent) {
      this.customSessionEvent = sessionEvent;
      this.customStackEvent = stackEvent;
    } else {
      throw new Error('session事件和stack事件必须同时存在');
    }
  }

  /**
   * 清除自定义事件
   */
  clearCustomEvent() {
    this.customSessionEvent = null;
    this.customStackEvent = null;
  }

  /**
   * 设置video播放dom
   * @param {Dom} videoRemote 远程视频播放video元素id
   * @param {Dom} videoLocal  本地视频播放video元素id
   */
  setVideoDom(videoRemoteId, videoLocalId) {
    this.oConfigCall.video_local = document.getElementById(videoLocalId);
    this.oConfigCall.video_remote = document.getElementById(videoRemoteId);
    console.log('远程视频播放video元素', this.oConfigCall.video_remote);
    console.log('本地视频播放video元素', this.oConfigCall.video_local);
  }

  /**
   * 清除播放dom
   */
  clearVideoDom() {
    this.oConfigCall.video_local = null;
    this.oConfigCall.video_remote = null;
  }

  /**
   * 播放video
   */
  playVideo() {
    console.log('开始播放');
    this.oConfigCall.video_local
      ? this.oConfigCall.video_local.play()
      : console.log('失败1');
    this.oConfigCall.video_remote
      ? this.oConfigCall.video_remote.play()
      : console.log('失败2');
  }

  /**
   * 注册
   * @param {Object} options 注册表单
   */
  register(options) {
    return sipRegister.call(this, options);
  }
  // SIP登出
  unRegister() {
    if (this.oSipStack) {
      console.log('软电话登出', this.name);
      this.oSipStack.stop();
    }
    Webrtc2Sip.instances.delete(this.name);
  }

  /**
   * 拨打
   * @param {String} phone 拨打号码
   * @param {String} callType 呼叫类型 audio语音，video视频，默认语音
   */
  sipCall(phone, callType) {
    if (!phone) return Promise.reject('拨打号码不能为空');
    if (this.oSipSessionCall) return Promise.reject('主叫号码非空闲');
    // call-audio
    this.oSipSessionCall = this.oSipStack.newSession(
      callType === 'video' ? 'call-audiovideo' : 'call-audio',
      this.oConfigCall
    );
    // make call
    if (this.oSipSessionCall.call(phone) != 0) {
      this.oSipSessionCall = null;
      return Promise.reject('呼叫失败');
    }
    return Promise.resolve('呼叫成功');
  }

  //接听
  accept() {
    if (this.oSipSessionCall) {
      this.oSipSessionCall.accept(this.oConfigCall);
    }
  }
  //拒接
  reject() {
    if (this.oSipSessionCall) {
      console.log('主手柄拒接');
      this.oSipSessionCall.reject(this.oConfigCall);
    }
  }
  // 挂机
  hangup() {
    if (this.oSipSessionCall) {
      this.oSipSessionCall.hangup({
        events_listener: {
          events: '*',
          listener: e => onSipEventSession.call(this, e),
        },
      });
    }
  }
  // 抢权
  sipSendRequestInfo() {
    if (this.oSipSessionCall) {
      this.oSipSessionCall.info('request', 'text/plain');
    } else {
      console.log('抢权失败');
    }
  }
  // 释放
  sipSendReleaseInfo() {
    if (this.oSipSessionCall) {
      this.oSipSessionCall.info('release', 'text/plain');
    } else {
      console.log('释放失败');
    }
  }

  static startRingTone() {
    try {
      this.ringtone.play();
    } catch (e) { }
  }
  static stopRingTone() {
    try {
      this.ringtone.pause();
    } catch (e) { }
  }
  static startRingbackTone() {
    try {
      this.ringbacktone.play();
    } catch (e) { }
  }
  static stopRingbackTone() {
    try {
      this.ringbacktone.pause();
    } catch (e) { }
  }
}

/**
 * 对象创建后配置
 */
function postConstruct(options) {
  this.oConfigCall = {
    audio_remote: Webrtc2Sip.audioRemote,
    video_local: Webrtc2Sip.videoLocal,
    video_remote: Webrtc2Sip.videoRemote,
    events_listener: {
      events: '*',
      listener: e => onSipEventSession.call(this, e),
    },
    sip_caps: [
      {
        name: '+g.oma.sip-im',
      },
      {
        name: 'language',
        value: '"en,fr"',
      },
    ],
  };
}

// sip注册
function sipRegister({
  displayName,
  phone,
  phoneType,
  password,
  sipHost,
  sipPort,
  wsHost,
  wsPort,
}) {
  try {
    const protocol = location.protocol == 'http:' ? 'ws://' : 'wss://'; // websocket协议
    const realm = `${sipHost}:${sipPort}`;

    this.oSipStack = new SIPml.Stack({
      realm: realm,
      impi: phone,
      impu: 'sip:' + phone + '@' + realm,
      password: password,
      display_name: displayName,
      // websocket_proxy_url: protocol + `${wsHost}:${wsPort}`,
      websocket_proxy_url: protocol + `${location.host}/webrtc2sip_ws`,
      outbound_proxy_url: 'udp://' + realm,
      ice_servers: '[]',
      enable_rtcweb_breaker: true,
      events_listener: {
        events: '*',
        listener: e => onSipEventStack.call(this, e),
      },
      enable_early_ims: true,
      enable_media_stream_cache: false,
      bandwidth: null,
      video_size: null,
      sip_headers: [
        {
          name: 'User-Agent',
          value: 'rtcweb/microsys',
        },
        {
          name: 'Organization',
          value: 'Microsys Telecom',
        },
      ],
    });
    if (this.oSipStack.start() !== 0) {
      return false;
    }
    Webrtc2Sip.webrtc2SipEnabled = true;
    this.name = phone; // webrtc2sip名称，用号码表示
    this.phoneType = phoneType; //号码类型
    Webrtc2Sip.instances.set(phone, this);
    return true;
  } catch (e) {
    return false;
  }
}

/**
 * SIP Stacks回调函数
 * @param e SIPml.Stack.Event
 */
function onSipEventStack(e) {
  tsk_utils_log_info('==stack event = ' + e.type);
  switch (e.type) {
    case 'started': {
      try {
        this.oSipSessionRegister = this.oSipStack.newSession('register', {
          expires: 100,
          events_listener: {
            events: '*',
            listener: e => onSipEventSession.call(this, e),
          },
          sip_caps: [
            {
              name: '+g.oma.sip-im',
              value: null,
            },
            //{ name: '+sip.ice' }, // rfc5768: FIXME doesn't work with Polycom TelePresence
            {
              name: '+audio',
              value: null,
            },
            {
              name: 'language',
              value: '"en,fr"',
            },
          ],
        });
        this.oSipSessionRegister.register();
      } catch (e) { }
      break;
    }
    case 'stopping':
    case 'stopped':
    case 'failed_to_start':
    case 'failed_to_stop': {
      var bFailure = e.type == 'failed_to_start' || e.type == 'failed_to_stop';
      this.oSipStack = null;
      this.oSipSessionRegister = null;
      this.oSipSessionCall = null;
      Webrtc2Sip.stopRingbackTone();
      Webrtc2Sip.stopRingTone();
      break;
    }

    case 'i_new_call': {
      for (let item of Webrtc2Sip.instances.values()) {
        if (item.oSipSessionCall) {
          // 已存在通话，则挂断
          e.newSession.hangup();
          return;
        }
      }
      this.oSipSessionCall = e.newSession;
      this.oSipSessionCall.setConfiguration(this.oConfigCall);
      e.incomingName = this.oSipSessionCall.getRemoteFriendlyName() || '未知';
      Webrtc2Sip.startRingTone();
      this.callType = e.newSession.o_session.media.e_type.s_name;
      break;
    }

    case 'm_permission_requested': {
      break;
    }
    case 'm_permission_accepted': {
      break;
    }
    case 'm_permission_refused': {
      Webrtc2Sip.stopRingbackTone();
      Webrtc2Sip.stopRingTone();
      break;
    }

    case 'starting':
    default:
      break;
  }
  const stackEvent =
    this.customStackEvent ||
    Webrtc2Sip.globalCustomStackEvent ||
    Webrtc2Sip.globalStackEvent;
  stackEvent(e, this);

  // this.customStackEvent
  //   ? this.customStackEvent(e, this)
  //   : Webrtc2Sip.globalStackEvent(e, this);
}

/**
 * SIPml sessions回调
 * @param {*} e SIPml.Session.Event
 */
function onSipEventSession(e) {
  tsk_utils_log_info('==session event = ' + e.type);
  switch (e.type) {
    case 'connecting':
    case 'connected': {
      var bConnected = e.type == 'connected';
      if (e.session == this.oSipSessionRegister) {
      } else if (e.session == this.oSipSessionCall) {
        if (bConnected) {
          Webrtc2Sip.stopRingbackTone();
          Webrtc2Sip.stopRingTone();
        }
      }
      break;
    } // 'connecting' | 'connected'
    case 'terminating':
    case 'terminated': {
      if (e.session == this.oSipSessionRegister) {
        this.oSipSessionCall = null;
        this.oSipSessionRegister = null;
      } else {
        this.oSipSessionCall = null;
        Webrtc2Sip.stopRingbackTone();
        Webrtc2Sip.stopRingTone();
      }
      // this.clearVideoDom();
      break;
    }

    case 'm_stream_video_local_added': {
      break;
    }
    case 'm_stream_video_local_removed': {
      break;
    }
    case 'm_stream_video_remote_added': {
      break;
    }
    case 'm_stream_video_remote_removed': {
      break;
    }
    case 'm_stream_audio_local_added':
    case 'm_stream_audio_local_removed':
    case 'm_stream_audio_remote_added':
    case 'm_stream_audio_remote_removed': {
      break;
    }
    case 'i_ect_new_call': {
      this.oSipSessionTransferCall = e.session;
      break;
    }
    case 'i_ao_request': {
      if (e.session == this.oSipSessionCall) {
        var iSipResponseCode = e.getSipResponseCode();
        if (iSipResponseCode == 180 || iSipResponseCode == 183) {
          Webrtc2Sip.startRingbackTone();
        }
      }
      break;
    }

    case 'm_early_media': {
      if (e.session == this.oSipSessionCall) {
        Webrtc2Sip.stopRingbackTone();
        Webrtc2Sip.stopRingTone();
      }
      break;
    }

    case 'm_local_hold_ok': {
      break;
    }
    case 'm_local_hold_nok': {
      if (e.session == this.oSipSessionCall) {
        this.oSipSessionCall.bTransfering = false;
      }
      break;
    }
    case 'm_local_resume_ok': {
      if (e.session == this.oSipSessionCall) {
        this.oSipSessionCall.bTransfering = false;
        this.oSipSessionCall.bHeld = false;
      }
      break;
    }
    case 'm_local_resume_nok': {
      if (e.session == this.oSipSessionCall) {
        this.oSipSessionCall.bTransfering = false;
      }
      break;
    }
    case 'm_remote_hold': {
      break;
    }
    case 'm_remote_resume': {
      break;
    }
    case 'm_bfcp_info': {
      break;
    }
    case 'o_ect_trying': {
      break;
    }
    case 'o_ect_accepted': {
      break;
    }
    case 'o_ect_completed':
    case 'i_ect_completed': {
      if (e.session == this.oSipSessionCall) {
        if (this.oSipSessionTransferCall) {
          this.oSipSessionCall = this.oSipSessionTransferCall;
        }
        this.oSipSessionTransferCall = null;
      }
      break;
    }
    case 'o_ect_failed':
    case 'i_ect_failed': {
      break;
    }
    case 'o_ect_notify':
    case 'i_ect_notify': {
      if (e.session == this.oSipSessionCall) {
        if (e.getSipResponseCode() >= 300) {
          if (this.oSipSessionCall.bHeld) {
            this.oSipSessionCall.resume();
          }
        }
      }
      break;
    }
    case 'i_ect_requested': {
      if (e.session == this.oSipSessionCall) {
        var s_message =
          '是否接受转接 [' + e.getTransferDestinationFriendlyName() + ']?'; //FIXME
        if (confirm(s_message)) {
          this.oSipSessionCall.acceptTransfer();
          break;
        }
        this.oSipSessionCall.rejectTransfer();
      }
      break;
    }
  } // globalCustomSessionEvent
  const sessionEvent =
    this.customSessionEvent ||
    Webrtc2Sip.globalCustomSessionEvent ||
    Webrtc2Sip.globalSessionEvent;
  sessionEvent(e, sessionType(e.session), this);
  // this.customSessionEvent
  //   ? this.customSessionEvent(e, sessionType(e.session), this)
  //   : Webrtc2Sip.globalSessionEvent(e, sessionType(e.session), this);
}

// 获取session类型
function sessionType(session) {
  if (session instanceof SIPml.Session.Registration) return 'Registration';
  else if (session instanceof SIPml.Session.Call) return 'Call';
  else if (session instanceof SIPml.Session.Event) return 'Event';
  else if (session instanceof SIPml.Session.Message) return 'Message';
  else if (session instanceof SIPml.Session.Publish) return 'Publish';
  else if (session instanceof SIPml.Session.Subscribe) return 'Subscribe';
  else return '';
}

export default Webrtc2Sip;
